/*
 * UAE - The Un*x Amiga Emulator
 *
 * Library of functions to make emulated filesystem as independent as
 * possible of the host filesystem's capabilities.
 *
 * Copyright 1999 Bernd Schmidt
 */

#pragma once

#ifndef FSDB_FILE
    #define FSDB_FILE L"_UAEFSDB.___"
#endif

#define FSDB_DIR_SEPARATOR '\\'
#define FSDB_DIR_SEPARATOR_S L"\\"

/* AmigaOS errors */
#define ERROR_BAD_NUMBER 6
#define ERROR_NO_FREE_STORE 103
#define ERROR_OBJECT_IN_USE 202
#define ERROR_OBJECT_EXISTS 203
#define ERROR_DIR_NOT_FOUND 204
#define ERROR_OBJECT_NOT_AROUND 205
#define ERROR_ACTION_NOT_KNOWN 209
#define ERROR_INVALID_LOCK 211
#define ERROR_OBJECT_WRONG_TYPE 212
#define ERROR_DISK_WRITE_PROTECTED 214
#define ERROR_DIRECTORY_NOT_EMPTY 216
#define ERROR_DEVICE_NOT_MOUNTED 218
#define ERROR_SEEK_ERROR 219
#define ERROR_COMMENT_TOO_BIG 220
#define ERROR_DISK_IS_FULL 221
#define ERROR_DELETE_PROTECTED 222
#define ERROR_WRITE_PROTECTED 223
#define ERROR_READ_PROTECTED 224
#define ERROR_NOT_A_DOS_DISK 225
#define ERROR_NO_DISK 226
#define ERROR_NO_MORE_ENTRIES 232
#define ERROR_NOT_IMPLEMENTED 236
#define ERROR_RECORD_NOT_LOCKED 240
#define ERROR_LOCK_COLLISION 241
#define ERROR_LOCK_TIMEOUT 242
#define ERROR_UNLOCK_ERROR 243

#define A_FIBF_HIDDEN (1 << 7)
#define A_FIBF_SCRIPT (1 << 6)
#define A_FIBF_PURE (1 << 5)
#define A_FIBF_ARCHIVE (1 << 4)
#define A_FIBF_READ (1 << 3)
#define A_FIBF_WRITE (1 << 2)
#define A_FIBF_EXECUTE (1 << 1)
#define A_FIBF_DELETE (1 << 0)

/* AmigaOS "keys" */
struct a_inode
{
    #ifdef AINO_DEBUG
    uint checksum1;
    #endif
    /* Circular list of recycleable a_inodes.  */
    a_inode* next, * prev;
    /* This a_inode's relatives in the directory structure.  */
    a_inode* parent;
    a_inode* child, * sibling;
    /* AmigaOS name, and host OS name.  The host OS name is a full path, the
     * AmigaOS name is relative to the parent.  */
    TCHAR* aname;
    TCHAR* nname;
    /* AmigaOS file comment, or nullptr if file has none.  */
    TCHAR* comment;
    /* AmigaOS protection bits.  */
    int amigaos_mode;
    /* Unique number for identification.  */
    uint uniq;
    /* For a directory that is being ExNext()ed, the number of child ainos
       which must be kept locked in core.  */
    uint locked_children;
    /* How many ExNext()s are going on in this directory?  */
    uint exnext_count;
    /* AmigaOS locking bits.  */
    int shlock;
    long db_offset;
    uint dir : 1;
    uint elock : 1;
    /* Nonzero if this came from an entry in our database.  */
    uint has_dbentry : 1;
    /* Nonzero if this will need an entry in our database.  */
    uint needs_dbentry : 1;
    /* This a_inode possibly needs writing back to the database.  */
    uint dirty : 1;
    /* If nonzero, this represents a deleted file; the corresponding
     * entry in the database must be cleared.  */
    uint deleted : 1;
    /* target volume flag */
    uint volflags;
    /* not equaling unit.mountcount -> not in this volume */
    uint mountcount;
    #ifdef AINO_DEBUG
    uint checksum2;
    #endif
};

extern TCHAR* nname_begin(TCHAR*);

// extern TCHAR * build_nname(const TCHAR* d, const TCHAR* n);
// extern TCHAR * build_aname(const TCHAR* d, const TCHAR* n);

/* Filesystem-independent functions.  */
extern void fsdb_clean_dir(a_inode*);
extern TCHAR* fsdb_search_dir(const TCHAR* dirname, TCHAR* rel);
extern void fsdb_dir_writeback(a_inode*);
extern int fsdb_used_as_nname(a_inode* base, const TCHAR*);
extern a_inode* fsdb_lookup_aino_aname(a_inode* base, const TCHAR*);
extern a_inode* fsdb_lookup_aino_nname(a_inode* base, const TCHAR*);
extern int fsdb_exists(TCHAR* nname);

/* Filesystem-dependent functions.  */
extern int fsdb_name_invalid(const TCHAR* n);
extern int fsdb_fill_file_attrs(a_inode*, a_inode*);
extern int fsdb_set_file_attrs(a_inode*);
extern int fsdb_mode_representable_p(const a_inode*, int);
extern int fsdb_mode_supported(const a_inode*);
extern TCHAR* fsdb_create_unique_nname(a_inode* base, const TCHAR*);

struct my_opendir_s;
struct my_openfile_s;

extern struct my_opendir_s* my_opendir(const TCHAR*, const TCHAR*);
extern struct my_opendir_s* my_opendir(const TCHAR*);
extern void my_closedir(struct my_opendir_s*);
extern int my_readdir(struct my_opendir_s*, TCHAR*);

extern int my_rmdir(const TCHAR*);
extern int my_mkdir(const TCHAR*);
extern int my_unlink(const TCHAR*);
extern int my_rename(const TCHAR*, const TCHAR*);
extern int my_setcurrentdir(const TCHAR* curdir, TCHAR* oldcur);
bool my_isfilehidden(const TCHAR* path);
void my_setfilehidden(const TCHAR* path, bool hidden);

extern struct my_openfile_s* my_open(const TCHAR*, int);
extern void my_close(struct my_openfile_s*);
extern long64 my_lseek(struct my_openfile_s*, long64, int);
extern uint my_read(struct my_openfile_s*, void*, uint);
extern uint my_write(struct my_openfile_s*, void*, uint);
extern int my_truncate(const TCHAR* name, ulong64 len);
extern int dos_errno();
extern int my_existsfile(const TCHAR* name);
extern int my_existsdir(const TCHAR* name);
extern FILE* my_opentext(const TCHAR*);

extern char* custom_fsdb_search_dir(const char* dirname, TCHAR* rel);
extern a_inode* custom_fsdb_lookup_aino_aname(a_inode* base, const TCHAR* aname);
extern a_inode* custom_fsdb_lookup_aino_nname(a_inode* base, const TCHAR* nname);
extern int custom_fsdb_used_as_nname(a_inode* base, const TCHAR* nname);

#define MYVOLUMEINFO_READONLY 1
#define MYVOLUMEINFO_STREAMS 2
#define MYVOLUMEINFO_ARCHIVE 4
#define MYVOLUMEINFO_REUSABLE 8

extern int my_getvolumeinfo(const TCHAR* root);